import asyncio

from aiogram import Bot, Dispatcher
from aiogram.fsm.storage.memory import MemoryStorage, SimpleEventIsolation
from aiogram.fsm.storage.redis import DefaultKeyBuilder, RedisStorage
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from sqlalchemy.orm import sessionmaker

from app.bot.dialogs import register_dialogs
from app.bot.handlers.admin.admin import register_admin_handlers
from app.bot.handlers.base import register_base_handlers
from app.bot.handlers.user.accounts import register_accounts_handlers
from app.bot.handlers.user.cabinet import register_cabinet_handlers
from app.bot.handlers.user.check_by_id import register_id_accounts_handlers
from app.bot.handlers.user.convert import register_convert_handlers
from app.bot.handlers.user.documents import register_documents_handlers
from app.bot.handlers.user.dolphin_account import register_dolphin_handlers
from app.bot.handlers.user.proxy_manual import register_manual_handlers
from app.bot.handlers.user.tasks import register_tasks_handlers
from app.bot.handlers.user.unique import register_unique_handlers
from app.bot.handlers.user.white_generator import register_white_generator_handlers
from app.bot.handlers.user.echo import register_echo_handlers
from app.bot.handlers.user.wlo_settings import register_wlo_settings_handlers
from app.bot.middlewares.config import ConfigMiddleware
from app.bot.middlewares.db import DBSessionMiddleware
from app.bot.middlewares.scheduler import SchedulerMiddleware
from app.bot.utils import notify
from app.bot.utils.logger import configure_logging, log
from app.bot.utils.scheduler import jobs
from app.bot.utils.scheduler.setup import setup_scheduler
from app.bot.utils.set_commands import set_commands
from app.config import Settings, load_config
from app.database.database import get_session_factory


def register_all_middlewares(
    dp, session_pool: sessionmaker, config: Settings, scheduler: AsyncIOScheduler
):
    dp.message.outer_middleware(DBSessionMiddleware(session_pool))
    dp.callback_query.outer_middleware(DBSessionMiddleware(session_pool))
    dp.message.outer_middleware(SchedulerMiddleware(scheduler))
    dp.callback_query.outer_middleware(ConfigMiddleware(config))
    dp.message.outer_middleware(ConfigMiddleware(config))
    dp.callback_query.outer_middleware(SchedulerMiddleware(scheduler))


def register_all_handlers(dp):
    register_base_handlers(dp)
    register_admin_handlers(dp)
    register_accounts_handlers(dp)
    register_cabinet_handlers(dp)
    register_tasks_handlers(dp)
    register_unique_handlers(dp)
    register_documents_handlers(dp)
    register_white_generator_handlers(dp)
    register_convert_handlers(dp)
    register_id_accounts_handlers(dp)
    register_dolphin_handlers(dp)
    register_manual_handlers(dp)
    register_wlo_settings_handlers(dp)
    # register_echo_handlers(dp)


async def main():

    configure_logging()
    log.info("Starting bot")

    config = load_config(".env")

    if config.tg_bot.use_redis:
        storage = RedisStorage.from_url(
            url=config.redis.url,
            key_builder=DefaultKeyBuilder(with_destiny=True),
        )
    else:
        storage = MemoryStorage()
    bot = Bot(token=config.tg_bot.token, parse_mode="HTML")
    dp = Dispatcher(storage=storage, events_isolation=SimpleEventIsolation())

    scheduler = setup_scheduler()
    session_factory = await get_session_factory(config)

    scheduler.add_job(
        jobs.check_accounts,
        "interval",
        hours=1,
        name="Accounts by id",
        args=(bot, session_factory, scheduler),
    )
    log.info(
        "Добавлена задача по проверке аккаунтов с статусами zagruzil doki и zagruzil selfy"
    )

    await set_commands(bot)
    await notify.start_notify(bot, config.tg_bot.admin_ids)

    register_all_middlewares(dp, session_factory, config, scheduler)
    register_all_handlers(dp)
    register_dialogs(dp)

    scheduler.start()
    await dp.start_polling(bot)


if __name__ == "__main__":
    try:
        asyncio.run(main())
    except (KeyboardInterrupt, SystemExit):
        log.error("Bot stopped!")
